一、Java特性
1. 特性
(1) 封装
封装指的是私有化,即隐藏具体属性和实现细节,仅对外开放接口,控制程序中属性的访问级别。
(2) 继承
子类拥有父类的所有属性和方法(除了 private
修饰的属性不能拥有),从而实现了代码的复用。
(3) 多态
对象在不同时刻表现出来的不同状态,最常见的即方法的重载和重写。
2. 接口
- 接口没有构造方法,不能实例化对象,只能通过接口实现使用。
- 一个类只能继承一个父类,而一个类却可以实现多个接口。
- 实现类通过
implements
关键字实现接口类,且必须重写除默认方法外的所有接口方法。 - 当接口方法声明为
default
时可包含方法体,实现类可选择是否重写,若未重写方法内容在调用时则执行默认方法体内容。 - 通过
static
可定义静态接口方法,接口方法可包含方法体,实现类无法重写静态接口方法。
public interface TestService {
/**
* 普通接口方法,无方法体,实现类必须重写
*/
int AddElem(int a, int b);
/**
* 默认接口方法,可包含方法体
*/
default void sayHello() {
System.out.println("Hello World !");
}
/**
* 静态接口方法,无法被实现类重写
*/
static void sayGoodbye() {
System.out.println("Goodbye.");
}
}
/**
* 实现类可以不实现默认方法,但必须重写普通方法
*/
public class TestServiceImpl implements TestService {
@Override
public int AddElem(int a, int b) {
return a + b;
}
}
public class InterfaceTest {
public static void main(String[] args) {
TestService service = new TestServiceImpl();
// 执行默认接口方法,打印 Hello World
service.sayHello();
// 通过接口类调用静态接口方法
TestService.sayGoodbye();
}
}
3. 抽象
抽象与接口类似,都是基于对应的共性抽象与多实现,其显著的一个区别在与抽象允许构造函数创建对象,因此可实现一些数据的初始化。
- 抽象类不能实例化对象
(new)
,只能通过被继承使用。 - 抽象方法通过
abstract
声明,没有方法体(同接口方方法)。 - 抽象类可以不包含抽象方法,但包含抽象方法的类必须声明为抽象类。
- 继承抽象类的子类必须重写其的抽象方法,或者声明自身为抽象类。
- 抽象类可以包含普通方法,其子类可选择是否重写,作用与普通类继承一致。
public abstract class AbsFather {
/**
* 抽象方法,子类必须进行重写或声明为抽象类
*/
public abstract int AddElem(int a, int b);
/**
* 普通方法,子类可选择性重写
*/
public void hello() {
System.out.println("Father say hello.");
}
}
/**
* 子类必须继承父类所以抽象方法,否则必须声明为抽象类
*/
public class AbsSon extends AbsFather {
/**
* 重写父类抽象方法
*/
@Override
public int AddElem(int a, int b) {
return a + b;
}
}
public class AbsTest {
public static void main(String[] args) {
// 通过子类实例化
AbsFather absSon = new AbsSon();
int sum = absSon.AddElem(10, 20);
System.out.println(sum);
// 执行父类 hello() 方法
absSon.hello();
}
}
二、关键字
1. this
当实例变量和方法形参重名冲突时,``this` 关键字指代实例变量。
public class Test {
int num = 1024;
public static void main(String[] args) {
printNum(2048);
}
public void printNum(int num) {
// 输出1024
System.out.println("Parameter num: " + num);
// 输出2048
System.out.println("Instance variable num: " + this.num);
}
}
2. static
(1) 类变量
static
修饰的变量为类变量,相同类的实例对象的类变量存储于同一内存,任何实例对象对其进行操作都会影响到其它实例对象对其访问。
类变量通常通过 类名.变量名
进行访问,而非实例对象。
public class Test {
static int staticNum = 4096;
public static void main(String[] args) {
printNum(2048);
}
public static void printNum(int num) {
System.out.println("Parameter num: " + num);
System.out.println("Parameter num: " + Test.staticNum);
}
}
(2) 静态块
static
除了用于修饰变量和方式之外,还可以以静态代码块的形式独立存在,当 main
执行时会根据静态块出现顺序执行。
需要注意一点,静态块中可以通过 类名.变量名
的形式访问静态变量,但无法直接访问实例变量,只能通过新建对象进行访问。
public class StaticTest {
private int num1; // 实例变量
private static int num2; // 静态变量
public static void main(String[] args) {
// 按静态块出现的先后顺序执行其方法体
}
static {
// 直接赋值 num1 = 10; 是非法的
StaticTest test = new StaticTest();
test.num1 = 10;
System.out.println("静态块 1 : " + test.num1);
}
static {
StaticTest.num2 = 20;
System.out.println("静态块 2 : " + num2);
}
}
三、基础概念
1. 方法重写
方法重写即当类实现接口或继承父类时,可对父类中的方法进行覆盖重写。
在 Java
中,如果两个对象在 equals()
方法中相等,那么它们的 hashCode()
值也必须相等。换句话说,两个对象的 hashCode()
值不同,则它们不可能相等,这是因为在常见的如 Map、HashMap
等集合中 hashCode()
值是用于确定对象在哈希表中的位置,以便进行高效的查找和访问。如果两个对象在 equals()
方法中相等,但它们的 hashCode()
值不同,那么它们可能会被放入哈希表中的不同位置,而不是预期的同一位置,这将导致在使用哈希表进行查找和访问时出现问题。因此若需要重写对象的 equlas()
方法时,需要同时重写其的 hashCode()
方法。
在实现 hashCode()
方法时,通常使用对象的属性值来计算一个整数,这个整数应该尽量不与其他对象的 hashCode()
值重复,从而保证不同对象由 hashCode()
计算得到的哈希值一定是不同的。
2. 方法重载
方法重载的体现方式为方法名相同,但参数的数量或者类型不同,最常见的即类的构造方法。
如下示例中的 User()
与 User(String id, String name)
即方法重载。
public class User {
private String id;
private String name;
public User() {
}
public User(String id, String name) {
this.id = id;
this.name = name;
}
}
3. 匿名类
匿名类 (Anonymous Class)
是一种没有名字的局部类,可以用来实现某个接口或继承某个类,通常用来编写简单的逻辑处理或回调函数。
匿名类的声明方式如下:
new SomeClass() {
// 实现接口或继承类的方法
};
4. 内部类
内部类 (Inner Class)
是一种定义在另一个类内部的类,可以被声明为私有、公共或受保护的。与匿名类不同的是,内部类可以有自己的名字和构造函数,而且可以继承其他类或实现接口。
内部类的作用范围可以是定义它的类的方法或代码块内部,也可以是其他类的方法或代码块内部(需要通过外部类的实例来创建内部类的实例)。
内部类的声明方式如下:
class OuterClass {
// ...
class InnerClass {
//...
}
}